/* hmci.c begin */

/*lint -esym(459, g_host_total_event) -esym(459, g_host_event) -esym(459, mmc_initialized)*/


#include "mmc_core.h"
#include "sdhci.h"
#include "proc/sdhci_proc.h"

/* local function declaration */
#include "linux/device.h"
#include "linux/platform_device.h"
#include "linux/module.h"

#define OFF_CLK2CARD_ON_DELAY 25


#define SDHCI_PLUG_STATE(h) (sdhc_readl(h, SDHC_PRESENT_STATE) & \
                SDHC_CARD_PRESENT)

#define CART_PLUG_STATE (SDHC_INT_CARD_INSERT | SDHC_INT_CARD_REMOVE)

/* Tuning Block Pattern UHS-I */
static const uint8_t tuning_blk_4bit[] = {
    0xFF, 0x0F, 0xFF, 0x00, 0xFF, 0xCC, 0xC3, 0xCC,
    0xC3, 0x3C, 0xCC, 0xFF, 0xFE, 0xFF, 0xFE, 0xEF,
    0xFF, 0xDF, 0xFF, 0xDD, 0xFF, 0xFB, 0xFF, 0xFB,
    0xBF, 0xFF, 0x7F, 0xFF, 0x77, 0xF7, 0xBD, 0xEF,
    0xFF, 0xF0, 0xFF, 0xF0, 0x0F, 0xFC, 0xCC, 0x3C,
    0xCC, 0x33, 0xCC, 0xCF, 0xFF, 0xEF, 0xFF, 0xEE,
    0xFF, 0xFD, 0xFF, 0xFD, 0xDF, 0xFF, 0xBF, 0xFF,
    0xBB, 0xFF, 0xF7, 0xFF, 0xF7, 0x7f, 0x7B, 0xDE,
};

/* Tuning block pattern for 8 bit mode for HS200 */
static const uint8_t tuning_blk_8bit[] = {
    0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x00,
    0xFF, 0xFF, 0xCC, 0xCC, 0xCC, 0x33, 0xCC, 0xCC,
    0xCC, 0x33, 0x33, 0xCC, 0xCC, 0xCC, 0xFF, 0xFF,
    0xFF, 0xEE, 0xFF, 0xFF, 0xFF, 0xEE, 0xEE, 0xFF,
    0xFF, 0xFF, 0xDD, 0xFF, 0xFF, 0xFF, 0xDD, 0xDD,
    0xFF, 0xFF, 0xFF, 0xBB, 0xFF, 0xFF, 0xFF, 0xBB,
    0xBB, 0xFF, 0xFF, 0xFF, 0x77, 0xFF, 0xFF, 0xFF,
    0x77, 0x77, 0xFF, 0x77, 0xBB, 0xDD, 0xEE, 0xFF,
    0xFF, 0xFF, 0xFF, 0x00, 0xFF, 0xFF, 0xFF, 0x00,
    0x00, 0xFF, 0xFF, 0xCC, 0xCC, 0xCC, 0x33, 0xCC,
    0xCC, 0xCC, 0x33, 0x33, 0xCC, 0xCC, 0xCC, 0xFF,
    0xFF, 0xFF, 0xEE, 0xFF, 0xFF, 0xFF, 0xEE, 0xEE,
    0xFF, 0xFF, 0xFF, 0xDD, 0xFF, 0xFF, 0xFF, 0xDD,
    0xDD, 0xFF, 0xFF, 0xFF, 0xBB, 0xFF, 0xFF, 0xFF,
    0xBB, 0xBB, 0xFF, 0xFF, 0xFF, 0x77, 0xFF, 0xFF,
    0xFF, 0x77, 0x77, 0xFF, 0x77, 0xBB, 0xDD, 0xEE,
};

struct tuning_blk_info {
    uint8_t *blk;
    unsigned int blk_size;
};

static irqreturn_t sdhci_irq(int irq, void *data);
void sdhci_init(struct sdhc_host *host, int soft);
void sd_hci_exec_cmd(struct sdhc_host *host, struct mmc_cmd *cmd,struct mmc_data *data);
void sdhci_sw_detect(AARCHPTR uwPar);

struct squirk_mmc_dev {
    int host_id;
    void *data;
    void (*preinit)(struct mmc_card *card, void *data);
};
static struct squirk_mmc_dev g_sq_dev[MAX_MMC_NUM] = {0};
static struct pthread_mutex drv_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;

int mmc_priv_fn_register(unsigned int id, void *data, void (*fn)(struct mmc_card *card, void *data))
{
    if (id >= MAX_MMC_NUM) {
        mmc_err("Id: invalid argument!\n");
        return -EINVAL;
    }
    g_sq_dev[id].host_id = id;
    g_sq_dev[id].data = data;
    g_sq_dev[id].preinit = fn;

    return 0;
}
void mmc_priv_fn(struct mmc_card *cur_card)
{
    struct mmc_host *host = cur_card->host;
    struct squirk_mmc_dev * g_sq_devp = &g_sq_dev[host->idx];

    if (g_sq_devp->host_id == host->idx && g_sq_devp->preinit)
        g_sq_devp->preinit(cur_card, g_sq_devp->data);
}

static void sdhci_dumpregs(struct sdhc_host *host)
{
    dprintf(": =========== DUMP (host%d) REGISTER===========\n", host->id);

    dprintf(  ": Sys addr: 0x%08x | Version:  0x%08x\n",
            sdhc_readl(host, SDHC_DMA_ADDRESS),
            sdhc_readw(host, SDHC_HOST_VERSION));
    dprintf(  ": Blk size: 0x%08x | Blk cnt:  0x%08x\n",
            sdhc_readw(host, SDHC_BLOCK_SIZE),
            sdhc_readw(host, SDHC_BLOCK_COUNT));
    dprintf(  ": Argument: 0x%08x | Trn mode: 0x%08x\n",
            sdhc_readl(host, SDHC_ARGUMENT),
            sdhc_readw(host, SDHC_TRANSFER_MODE));
    dprintf(  ": Present:  0x%08x | Host ctl: 0x%08x\n",
            sdhc_readl(host, SDHC_PRESENT_STATE),
            sdhc_readb(host, SDHC_HOST_CONTROL));
    dprintf(  ": Power:    0x%08x | Blk gap:  0x%08x\n",
            sdhc_readb(host, SDHC_POWER_CONTROL),
            sdhc_readb(host, SDHC_BLOCK_GAP_CONTROL));
    dprintf(  ": Wake-up:  0x%08x | Clock:    0x%08x\n",
            sdhc_readb(host, SDHC_WAKE_UP_CONTROL),
            sdhc_readw(host, SDHC_CLOCK_CONTROL));
    dprintf(  ": Timeout:  0x%08x | Int stat: 0x%08x\n",
            sdhc_readb(host, SDHC_TIMEOUT_CONTROL),
            sdhc_readl(host, SDHC_INT_STATUS));
    dprintf(  ": Int enab: 0x%08x | Sig enab: 0x%08x\n",
            sdhc_readl(host, SDHC_INT_ENABLE),
            sdhc_readl(host, SDHC_SIGNAL_ENABLE));
    dprintf(  ": ACMD err: 0x%08x | Slot int: 0x%08x\n",
            sdhc_readw(host, SDHC_AUTO_CMD_ERR),
            sdhc_readw(host, SDHC_SLOT_INT_STATUS));
    dprintf(  ": Caps:     0x%08x | Caps_1:   0x%08x\n",
            sdhc_readl(host, SDHC_CAPABILITIES),
            sdhc_readl(host, SDHC_CAPABILITIES_1));
    dprintf(  ": Cmd:      0x%08x | Max curr: 0x%08x | opcode = %d\n",
            sdhc_readw(host, SDHC_COMMAND),
            sdhc_readl(host, SDHC_MAX_CURRENT),
            (sdhc_readw(host, SDHC_COMMAND) >> 8) & 0x1f);
    dprintf(  ": Resp 1:   0x%08x | Resp 0:   0x%08x\n",
            sdhc_readl(host, SDHC_RESPONSE + 0x4),
            sdhc_readl(host, SDHC_RESPONSE));
    dprintf(  ": Resp 3:   0x%08x | Resp 2:   0x%08x\n",
            sdhc_readl(host, SDHC_RESPONSE + 0xC),
            sdhc_readl(host, SDHC_RESPONSE + 0x8));
    dprintf(  ": Host ctl2: 0x%08x\n",
            sdhc_readw(host, SDHC_HOST_CONTROL2));

    if (host->flags & SDHC_USE_ADMA_64BIT) {
        dprintf(  ": ADMA Err: 0x%08x\n",
                readl((AARCHPTR)host->base + SDHC_ADMA_ERROR));
        dprintf(  ": ADMA Addr(0:31): 0x%08x | ADMA Addr(32:63): 0x%08x\n",
                readl((AARCHPTR)host->base + SDHC_ADMA_ADDRESS_LOW),
                readl((AARCHPTR)host->base + SDHC_ADMA_ADDRESS_HIGH));
    } else if (host->flags & SDHC_USE_ADMA) {
        dprintf(  ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
                readl((AARCHPTR)host->base + SDHC_ADMA_ERROR),
                readl((AARCHPTR)host->base + SDHC_ADMA_ADDRESS_LOW));
    }

    dprintf(": ===========================================\n");
}


void mmc_dma_cache_inv(void *addr, unsigned int size)
{
    AARCHPTR start = (AARCHPTR)addr & ~(CACHE_ALIGNED_SIZE - 1);
    AARCHPTR end = (AARCHPTR)addr + size;

    end = ALIGN(end, CACHE_ALIGNED_SIZE);

    dma_cache_inv(start, end);
}

void mmc_dma_cache_clean(void *addr, unsigned int size)
{
    AARCHPTR start = (AARCHPTR)addr & ~(CACHE_ALIGNED_SIZE - 1);
    AARCHPTR end = (AARCHPTR)addr + size;

    end = ALIGN(end, CACHE_ALIGNED_SIZE);

    dma_cache_clean(start, end);
}

static void sdhci_set_card_detection(struct sdhc_host *host, bool enable)
{
    unsigned int present;

    if (host->mmc->caps.bits.cap_nonremovable ||
            host->forceSWDetect || SDHC_DETECTION_BROKEN(host))
        return;

    if (enable) {
        present = sdhc_readl(host, SDHC_PRESENT_STATE) &
            SDHC_CARD_PRESENT;

        host->irq_enable |= present ? SDHC_INT_CARD_REMOVE :
            SDHC_INT_CARD_INSERT;
    } else {
        host->irq_enable &= ~(SDHC_INT_CARD_REMOVE | SDHC_INT_CARD_INSERT);
    }
}

void SDHCI_EnableSample(struct sdhc_host *host)
{
    unsigned int reg;

    reg = sdhc_readl(host, SDHC_AUTO_TUNING_CTRL);
    reg |= SDHC_SW_TUNING_EN;
    sdhc_writel(host, reg, SDHC_AUTO_TUNING_CTRL);
}

void sdhci_enable_card_detection(struct sdhc_host *host)
{
    sdhci_set_card_detection(host, true);
    sdhc_writel(host, host->irq_enable, SDHC_INT_ENABLE);
    sdhc_writel(host, host->irq_enable, SDHC_SIGNAL_ENABLE);
}

int mmc_get_host_idx(struct mmc_host *mmc, uint32_t * id)
{
    struct sdhc_host *host = mmc->priv;

    if (host == NULL) {
        mmc_err("host is NULL!\n");
        return -EIO;
    }

    if (id == NULL)
    {
        return -EINVAL;
    }

    *id = host->id;
    return 0;
}

uint32_t get_mmc_max_num(void)
{
    return MAX_MMC_NUM;

}

static int sdhci_do_get_cd(struct sdhc_host *host)
{
    struct mmc_host * mmc = NULL;
    struct mmc_card *card = NULL;

    if (host->flags & SDHC_DEVICE_DEAD)
        return 0;

    mmc = host->mmc;
    card = mmc->card_cur;
    if (host->quirks.bits.quirk_broken_card_detection ||
            (host->mmc->caps.bits.cap_nonremovable) ||
                        host->forceSWDetect) {
        if (card != NULL && is_card_present(card)) {
            return 0;
        } else {
            return 1;
        }
    }
    return !!(sdhc_readl(host, SDHC_PRESENT_STATE) & SDHC_CARD_PRESENT);
}

int mmc_get_card_detect(struct mmc_host *mmc)
{
    struct sdhc_host *host = mmc->priv;
    int status = 0;
    status = sdhci_do_get_cd(host);
    return status;
}

static void sdhci_en_preset_value(struct sdhc_host *host, bool en)
{
    if (host->version < SDHC_SPEC_300)
        return;


    if (host->preset_enabled != en) {
        unsigned int ctrl_val = sdhc_readw(host, SDHC_HOST_CONTROL2);

        if (en) {
            ctrl_val |= SDHC_CTRL_PRESET_VAL_ENABLE;
        } else {
            ctrl_val &= ~SDHC_CTRL_PRESET_VAL_ENABLE;
        }

        sdhc_writew(host, ctrl_val, SDHC_HOST_CONTROL2);

        if (en) {
            host->flags |= SDHC_PV_ENABLED;
        } else {
            host->flags &= ~SDHC_PV_ENABLED;
        }

        host->preset_enabled = en;
    }
}

void mmc_set_timing(struct mmc_host *mmc, enum mmc_bus_timing timing)
{
    struct sdhc_host * host = mmc->priv;
    unsigned int clockval;
    unsigned int ctrl, ctrl_2;

    ctrl = sdhc_readb(host, SDHC_HOST_CONTROL);

    if (timing >= TIMING_MMC_HS)
        ctrl |= SDHC_CTRL_HISPD;

    if (host->version < SDHC_SPEC_300) {
        sdhc_writeb(host, ctrl, SDHC_HOST_CONTROL);
        return;
    }

    if (!host->preset_enabled) {
        sdhc_writeb(host, ctrl, SDHC_HOST_CONTROL);
        ctrl_2 = sdhc_readw(host, SDHC_HOST_CONTROL2);
        ctrl_2 &= ~SDHC_CTRL_DRV_TYPE_MASK;

        sdhc_writew(host, ctrl_2, SDHC_HOST_CONTROL2);
    } else {
        clockval = sdhc_readw(host, SDHC_CLOCK_CONTROL);
        clockval &= ~SDHC_CLOCK_CARD_EN;
        sdhc_writew(host, clockval, SDHC_CLOCK_CONTROL);

        sdhc_writeb(host, ctrl, SDHC_HOST_CONTROL);
        mmc_set_clock(mmc, host->clock);
    }
    clockval = sdhc_readw(host, SDHC_CLOCK_CONTROL);
    clockval &= ~SDHC_CLOCK_CARD_EN;
    sdhc_writew(host, clockval, SDHC_CLOCK_CONTROL);

    sdhci_set_uhs_signaling(host, timing);
    host->timing = timing;
    if ((timing > TIMING_UHS_SDR12)
            && (timing <= TIMING_UHS_DDR50))
        sdhci_en_preset_value(host, true);
    mmc_set_clock(mmc, host->clock);
}

static void sdhci_reinit(struct sdhc_host *cur_host)
{
    sdhci_init(cur_host, 0);

    if (cur_host->flags & SDHC_USING_RETUNING_TIMER) {
        cur_host->flags &= ~SDHC_USING_RETUNING_TIMER;
        cur_host->mmc->max_blk_num = 65535;
    }
    sdhci_enable_card_detection(cur_host);
}

void mmc_set_power_mode(struct mmc_host *mmc, enum mmc_power_mode mode)
{
    struct sdhc_host *cur_host = mmc->priv;
    unsigned int vdd = mmc->dvdd;
    unsigned int pwr = SDHC_POWER_330;

    (void)vdd; //make compiler happy
    mmc_trace(3,"host->pwr = 0x%x, vdd value =%d\n",cur_host->pwr, vdd);

    if (POWER_OFF == mode) {
        sdhc_writel(cur_host, 0, SDHC_SIGNAL_ENABLE);
        sdhci_reinit(cur_host);
    } else {
        if (cur_host->version >= SDHC_SPEC_300)
            sdhci_en_preset_value(cur_host, false);

        if (cur_host->pwr == SDHC_POWER_330)
            return;

        cur_host->pwr = pwr;

        sdhc_writeb(cur_host, 0, SDHC_POWER_CONTROL);
        sdhc_writeb(cur_host, pwr, SDHC_POWER_CONTROL);
        pwr |= SDHC_POWER_ON;
        sdhc_writeb(cur_host, pwr, SDHC_POWER_CONTROL);
        mmc_delay_ms(10);
    }
}/*lint !e529*//*'vdd' not subsequently referenced*/

void mmc_set_bus_width(struct mmc_host *mmc, enum mmc_bus_width width)
{
    unsigned char ctrl_val = 0;
    struct sdhc_host * host = mmc->priv;

    ctrl_val = sdhc_readb(host, SDHC_HOST_CONTROL);
    if (width == BUS_WIDTH_8) {
        ctrl_val &= ~SDHC_CTRL_4BITBUS;
        if (host->version >= SDHC_SPEC_300)
            ctrl_val |= SDHC_CTRL_8BITBUS;
    } else {
        if (host->version >= SDHC_SPEC_300)
            ctrl_val &= ~SDHC_CTRL_8BITBUS;
        if (width == BUS_WIDTH_4)
            ctrl_val |= SDHC_CTRL_4BITBUS;
        else
            ctrl_val &= ~SDHC_CTRL_4BITBUS;
    }
    sdhc_writeb(host, ctrl_val, SDHC_HOST_CONTROL);
}

void SDHCI_CardClk(struct sdhc_host *host, int action)
{
    unsigned int value;

    value = sdhc_readl(host, SDHC_CLK_CTRL);
    if (action == 0) {
        // close the clock gate
        value &= ~SDHC_CLK_CTRL_CLK_EN;
    } else {
        // open the clk of interface
        value |= SDHC_CLK_CTRL_CLK_EN;
    }
    sdhc_writel(host, value, SDHC_CLK_CTRL);
}

void mmc_set_clock(struct mmc_host *mmc, unsigned int clocknum)
{
    struct sdhc_host * host = (struct sdhc_host *)mmc->priv;
    unsigned short clk = 0;
    unsigned long timeout_val;
    unsigned int ret = 0;

    // turn off clk2card_on
    clk = sdhc_readw(host, SDHC_CLOCK_CONTROL);
    clk &= ~(SDHC_CLOCK_CARD_EN);
    sdhc_writew(host, clk, SDHC_CLOCK_CONTROL);
    LOS_Udelay(OFF_CLK2CARD_ON_DELAY);

    // turn off card_clk_en
    clk &= ~(SDHC_CLOCK_INT_EN | SDHC_CLOCK_PLL_EN);
    sdhc_writew(host, clk, SDHC_CLOCK_CONTROL);

    if (clocknum == 0)
        return;


    if (clocknum >= host->max_clk) {
        clocknum = host->max_clk;
    }

    sdhci_hisi_assert_reset_dll(host);

    SDHCI_SetPhase(host);

    ret = sdhci_set_clock(host, clocknum);
    if (!ret) {
        mmc_err("Set clock fail!\n");
        return;
    }
    if (!mmc->caps.bits.cap_nonremovable)
        sdhci_hisi_deassert_reset_dll(host);

    host->clock = clocknum;

    sdhci_hisi_set_drv_dll(host);

    // turn on card_clk_en
    clk |= SDHC_CLOCK_INT_EN | SDHC_CLOCK_PLL_EN;
    sdhc_writew(host, clk, SDHC_CLOCK_CONTROL);

    timeout_val = 20;
    while (1) {
        clk = sdhc_readw(host, SDHC_CLOCK_CONTROL);
        if (clk & (unsigned short)SDHC_CLOCK_INT_STABLE) {
            break;
        }
        if (timeout_val == 0) {
            mmc_err("Internal clock never stabilized.\n");
            return;
        }
        timeout_val--;
        mmc_delay_ms(1);
    }

    sdhci_hisi_deassert_reset_dll(host);

    // turn on clk2card_on
    clk |= SDHC_CLOCK_CARD_EN;
    sdhc_writew(host, clk, SDHC_CLOCK_CONTROL);
}

void mmc_hw_reset(struct mmc_host *mmc)
{
    struct sdhc_host * host = mmc->priv;

    sdhc_writel(host, 0x0, SDHC_EMMC_HW_RESET);
    mmc_delay_us(10);
    sdhc_writel(host, 0x1, SDHC_EMMC_HW_RESET);
    mmc_delay_us(200);
}

void mmc_hw_init(struct mmc_host *mmc)
{

}

void sdhci_enable_plug_irq(struct sdhc_host* cur_host, unsigned int irq)
{
    sdhc_writel(cur_host, irq, SDHC_INT_ENABLE);
    sdhc_writel(cur_host, irq, SDHC_SIGNAL_ENABLE);
}

void mmc_set_sdio_irq(struct mmc_host *mmc, int enable)
{
    struct sdhc_host * cur_host = mmc->priv;

    if (enable)
        cur_host->flags |= SDHC_SDIO_IRQ_ENABLED;
    else
        cur_host->flags &= ~SDHC_SDIO_IRQ_ENABLED;

    if (!(cur_host->flags & SDHC_DEVICE_DEAD)) {
        if (enable)
            cur_host->irq_enable |= SDHC_INT_CARD_INT;
        else
            cur_host->irq_enable &= ~SDHC_INT_CARD_INT;

        sdhci_enable_plug_irq(cur_host, cur_host->irq_enable);
    }
}

static int sdhci_check_readonly(struct sdhc_host *host)
{
    int is_readonly;

    if (host->flags & SDHC_DEVICE_DEAD)
        is_readonly = 0;
    else
        is_readonly = !(sdhc_readl(host, SDHC_PRESENT_STATE)
                & SDHC_WRITE_PROTECT);

    return host->quirks.bits.quirk_inverted_write_protect?
        !is_readonly : is_readonly;
}


#define SAMPLE_COUNT    5
static int sdhci_do_get_ro(struct sdhc_host *host)
{
    int j, ro_cnt = 0;

    if (!host->quirks.bits.quirk_unstable_ro_detect)
        return sdhci_check_readonly(host);

    for (j = 0; j < SAMPLE_COUNT; j++) {
        if (sdhci_check_readonly(host)) {
            if (++ro_cnt > SAMPLE_COUNT / 2)
                return 1;
        }
        msleep(20);
    }
    return 0;
}

int mmc_get_readonly(struct mmc_host *mmc)
{
    struct sdhc_host *host = mmc->priv;
    int retval = 0;
    retval = sdhci_do_get_ro(host);
    return retval;
}


void mmc_set_bus_mode(struct mmc_host *mmc, enum bus_mode mode)
{

}

/* those func may different on other platform.*/
void sdhci_reset(struct sdhc_host *cur_host, unsigned char mask)
{
    unsigned long timeout_val;

    sdhc_writeb(cur_host, mask, SDHC_SOFTWARE_RESET);

    if (mask & SDHC_RESET_ALL)
        cur_host->clock = 0;

    timeout_val = 100;

    /* hw clears the bit when it's done */
    while (sdhc_readb(cur_host, SDHC_SOFTWARE_RESET) & mask) {
        if (timeout_val == 0) {
            mmc_err("host%d: Reset 0x%x never completed.\n",
                    cur_host->id, (int)mask);
            sdhci_dumpregs(cur_host);
            return;
        }
        timeout_val--;
        mmc_delay_ms(1);
    }
}

static void sdhci_do_reset(struct sdhc_host *cur_host, unsigned int mask)
{
    sdhci_reset(cur_host, mask);

    if (mask & SDHC_RESET_ALL)
        cur_host->preset_enabled = false;
}


void sdhci_init(struct sdhc_host *cur_host, int soft)
{
    unsigned int reg;
    if (soft)
        sdhci_do_reset(cur_host, SDHC_RESET_CMD|SDHC_RESET_DATA);
    else
        sdhci_do_reset(cur_host, SDHC_RESET_ALL);

    cur_host->pwr = 0;
    cur_host->irq_enable = SDHC_INT_BUS_POWER | SDHC_INT_DATA_END_BIT |
        SDHC_INT_DATA_CRC | SDHC_INT_DATA_TIMEOUT |
        SDHC_INT_INDEX | SDHC_INT_END_BIT | SDHC_INT_CRC |
        SDHC_INT_TIMEOUT | SDHC_INT_DATA_END |
        SDHC_INT_RESPONSE | SDHC_INT_AUTO_CMD_ERR;

   sdhci_enable_plug_irq(cur_host, cur_host->irq_enable);

    if (soft) {
        cur_host->clock = 0;
    } else {
        reg = sdhc_readw(cur_host, SDHC_MSHC_CTRL);
        reg &= ~SDHC_CMD_CONFLIT_CHECK;
        sdhc_writew(cur_host, reg, SDHC_MSHC_CTRL);

        reg = sdhc_readl(cur_host, SDHC_AXI_MBIIU_CTRL);
        reg &= ~(SDHC_GM_WR_OSRC_LMT_MASK | SDHC_GM_RD_OSRC_LMT_MASK | SDHC_UNDEFL_INCR_EN);
        reg |= SDHC_GM_WR_OSRC_LMT_VAL | SDHC_GM_RD_OSRC_LMT_VAL;
        sdhc_writel(cur_host, reg, SDHC_AXI_MBIIU_CTRL);

        reg = sdhc_readl(cur_host, SDHC_MULTI_CYCLE);
        reg |= SDHC_EDGE_DETECT_EN | SDHC_DATA_DLY_EN;
        reg &= ~SDHC_CMD_DLY_EN;
        sdhc_writel(cur_host, reg, SDHC_MULTI_CYCLE);
    }
}

void sdhci_tasklet_finish(struct sdhc_host *cur_host)
{
    struct mmc_request *mrq = NULL;

    mmc_assert(cur_host);
    if (cur_host->mrq == NULL)
        return;

    mrq = cur_host->mrq;
    mmc_assert(mrq);

    if (!(cur_host->flags & SDHC_DEVICE_DEAD) && ((mrq->cmd && mrq->cmd->err) ||
             (mrq->data && mrq->data->err))) {
        sdhci_do_reset(cur_host, SDHC_RESET_CMD);
        sdhci_do_reset(cur_host, SDHC_RESET_DATA);
    }
    cur_host->mrq = NULL;
    cur_host->cmd = NULL;
    cur_host->data = NULL;

    if (mrq->done != NULL)
        mrq->done(mrq);
    (void)mmc_event_signal(&cur_host->sdhci_event, SDHC_PEND_REQUEST_DONE);
}

static void sdhci_set_blk_size_reg(struct sdhc_host *host,
        unsigned int blksz, unsigned int sdma_boundary)
{
    if (host->flags & SDHC_USE_ADMA)
        sdhc_writel(host, SDHC_MAKE_BLKSZ(7, blksz),
                SDHC_BLOCK_SIZE);
    else
        sdhc_writel(host, SDHC_MAKE_BLKSZ(sdma_boundary, blksz),
                SDHC_BLOCK_SIZE);
}

static void sdhci_set_adma_desc(struct sdhc_host *host,
        char *desc, dma_addr_t addr,
        int len, unsigned cmd)
{
    unsigned short* cmdlen = (unsigned short *)desc;

    cmdlen[0] = (cmd);
    cmdlen[1] = (len);

    if (host->flags & SDHC_USE_ADMA_64BIT) {
        unsigned long *dataddr = (unsigned long*)(desc + 4);
        dataddr[0] = (addr);
    } else {
        unsigned int *dataddr = (unsigned int*)(desc + 4);
        dataddr[0] = (addr);
    }
}

static void sdhci_adma_mark_end(void *desc)
{
    unsigned short* d = (unsigned short *)desc;
    d[0] |= ADMA2_END;
}
static int sdhci_adma_table_pre(struct sdhc_host *host, struct mmc_data *data)
{
    char *adma_desc = NULL;
    int i = 0;

    dma_addr_t addr = 0;
    int len = 0;

    unsigned int dma_dir;

    if (data->data_flags & MMC_DATA_READ)
        dma_dir = DMA_FROM_DEVICE;
    else
        dma_dir = DMA_TO_DEVICE;

    host->sg_count = data->sg_len;
    adma_desc = host->adma_desc;

    (void)memset_s(host->adma_desc,ALIGN(host->adma_desc_sz,CACHE_ALIGNED_SIZE),0,ALIGN(host->adma_desc_sz,CACHE_ALIGNED_SIZE));

    for(i = 0; i < host->sg_count; i++) {
        addr = sg_dma_address(&data->sg[i]);
        len = sg_dma_len(&data->sg[i]);

        if (DMA_TO_DEVICE == dma_dir)
            mmc_dma_cache_clean((void*)addr, len);
        else
            mmc_dma_cache_inv((void*)addr, len);

        do
        {
            if (len > 0x1000) {
                sdhci_set_adma_desc(host, adma_desc, addr, 0x1000, 0x21);
                len -= 0x1000;
                addr += 0x1000;
            }
            else {
                sdhci_set_adma_desc(host, adma_desc, addr, len, 0x21);
                len = 0;
            }
            adma_desc += host->adma_desc_line_sz;
        } while(len);

        if ((unsigned int)(adma_desc - host->adma_desc) > host->adma_desc_sz)
            mmc_trace(5,"check something wrong!\n");
    }

    if (host->quirks.bits.quirk_no_endattr_in_nopdesc) {
            /* Mark the last descriptor as the terminating descriptor */
            if (adma_desc != host->adma_desc) {
                adma_desc -= host->adma_desc_line_sz;
                sdhci_adma_mark_end(adma_desc);
            }
    } else {
        sdhci_set_adma_desc(host, adma_desc, 0, 0, 0x3);
    }
    mmc_dma_cache_clean((void*)host->adma_desc, ALIGN(host->adma_desc_sz,CACHE_ALIGNED_SIZE));

    return 0;
}

static void sdhci_set_tsf_irqs(struct sdhc_host *host)
{
    unsigned int pio_irqs = SDHC_INT_DATA_AVAIL | SDHC_INT_SPACE_AVAIL;
    unsigned int dma_irqs = SDHC_INT_DMA_END | SDHC_INT_ADMA_ERROR;

    if (host->flags & SDHC_REQ_USE_DMA)
        host->irq_enable = (host->irq_enable & ~pio_irqs) | dma_irqs;
    else
        host->irq_enable = (host->irq_enable & ~dma_irqs) | pio_irqs;

   sdhci_enable_plug_irq(host, host->irq_enable);
}

static void sdhci_prepare_data(struct sdhc_host *host)
{
    unsigned char ctrl;
    struct mmc_data * data = host->data;
    struct mmc_cmd * cmd = host->cmd;
    int retval = 0;

    /* set timeout value , use default value. */
    if (data != NULL || (cmd->resp_type & RESP_BUSY))
        sdhc_writeb(host, SDHC_DEFINE_TIMEOUT, SDHC_TIMEOUT_CONTROL);

    if (NULL == data)
        return;

    mmc_trace(3,"data->blocksz = %d,data->blocks = %d,host->mmc->max_request_size = %d\n",
            data->blocksz,data->blocks,host->mmc->max_request_size);
    mmc_assert(((data->blocksz * data->blocks) < (host->mmc->max_request_size)));
    mmc_assert(data->blocksz < host->mmc->max_blk_size);
    mmc_assert(data->blocks < 65535);

    host->data->xfered = 0;

    if (host->flags & (SDHC_USE_ADMA | SDHC_USE_SDMA))
        host->flags |= SDHC_REQ_USE_DMA;

    if (host->flags & SDHC_REQ_USE_DMA) {
        if (host->flags & SDHC_USE_ADMA) {
            /*   ADMA config */
            retval = sdhci_adma_table_pre(host, data);
            if (retval) {
                host->flags &= ~SDHC_REQ_USE_DMA;
            } else {
                sdhc_writel(host, 0, SDHC_DMA_ADDRESS);
                sdhci_adma_config(host);
            }
        } else {
            /*   SDMA config */
            int sg_count;

            sg_count = data->sg_len;
            if (sg_count!= 1)
                    mmc_err("sg_count should be one!\n");
            else
                sdhc_writel(host, sg_dma_address(&data->sg[0]), SDHC_DMA_ADDRESS);
        }
    }

    if (host->version >= SDHC_SPEC_200) {
        ctrl = sdhc_readb(host, SDHC_HOST_CONTROL);
        ctrl &= ~SDHC_CTRL_DMA_MASK;
        if ((host->flags & SDHC_REQ_USE_DMA) &&
                (host->flags & SDHC_USE_ADMA)) {
            if (host->flags & SDHC_USE_ADMA_64BIT)
                ctrl |= SDHC_CTRL_ADMA64;
            else
                ctrl |= SDHC_CTRL_ADMA32;
        } else {
            ctrl |= SDHC_CTRL_SDMA;
        }
        sdhc_writeb(host, ctrl, SDHC_HOST_CONTROL);
    }


    sdhci_set_tsf_irqs(host);

    sdhci_set_blk_size_reg(host, data->blocksz, SDHC_DEFAULT_BOUNDARY_ARG);
    sdhc_writew(host, data->blocks, SDHC_BLOCK_COUNT);
}

static void sdhci_set_tsf_mode(struct sdhc_host *host, struct mmc_cmd *cmd)
{
    unsigned short mode;
    struct mmc_data * data = host->data;

    if (data == NULL) {
        mode = sdhc_readw(host, SDHC_TRANSFER_MODE);
        sdhc_writew(host, mode & ~(SDHC_TRNS_AUTO_CMD12 |
                    SDHC_TRNS_AUTO_CMD23), SDHC_TRANSFER_MODE);
        return;
    }

    mode = SDHC_TRNS_BLK_CNT_EN;
    if (cmd->cmd_code == WRITE_MULTIPLE_BLOCK ||
           cmd->cmd_code == READ_MULTIPLE_BLOCK || data->blocks > 1) {
        mode |= SDHC_TRNS_MULTI;
        if ((host->flags & SDHC_AUTO_CMD12)) {
            mode |= SDHC_TRNS_AUTO_CMD12;
        }
        else if ((host->flags & SDHC_AUTO_CMD23)) {
            mode |= SDHC_TRNS_AUTO_CMD23;
            sdhc_writel(host, data->blocks, SDHC_ARGUMENT2);
        }
    }

    if (data->data_flags & MMC_DATA_READ)
        mode |= SDHC_TRNS_READ;
    if (host->flags & SDHC_REQ_USE_DMA)
        mode |= SDHC_TRNS_DMA;

    sdhc_writew(host, mode, SDHC_TRANSFER_MODE);
}

static void sdhci_finish_data(struct sdhc_host *cur_host)
{
    struct mmc_data *data = NULL;

    mmc_assert(cur_host->data);

    mmc_trace(5,"intr status:0x%x\n", sdhc_readl(cur_host, SDHC_INT_STATUS));
    data = cur_host->data;

    if (!data->err)
        data->xfered = data->blocks * data->blocksz;
    else
        data->xfered = 0;

    if (MMC_CMD_STOPENABLE(data)) {
        if (data->err) {
            sdhci_do_reset(cur_host, SDHC_RESET_CMD);
            sdhci_do_reset(cur_host, SDHC_RESET_DATA);
        }
        mmc_trace(4,"cur_host=%p,cur_host->cmd->cmd_code = %d\n",cur_host,cur_host->cmd->cmd_code);
        sd_hci_exec_cmd(cur_host, &(data->cmd_stop), NULL);
    } else
        sdhci_tasklet_finish(cur_host);
}

void sd_hci_exec_cmd(struct sdhc_host *host,
        struct mmc_cmd *cmd, struct mmc_data *data)
{
    unsigned int flags = 0;
    unsigned int mask;
    unsigned long timeout_val = 10; // 10ms

    mask = SDHC_CMD_INHIBIT;
    if ((data != NULL) || (cmd->resp_type & RESP_BUSY))
        mask |= SDHC_DATA_INHIBIT;

    if (data != NULL && MMC_CMD_STOPENABLE(data))
        mask &= ~SDHC_DATA_INHIBIT;

    /* wait host ready */
    while(sdhc_readl(host, SDHC_PRESENT_STATE) & mask) {
        if (timeout_val == 0) {
            mmc_trace(9,"exec cmd %d timeout!\n", cmd->cmd_code);
            sdhci_dumpregs(host);
            cmd->err = -EIO;
            sdhci_tasklet_finish(host);
            return;
        }
        timeout_val--;
        mmc_delay_ms(1);
    }

    host->cmd = cmd;

    host->busy_handle = 0;

    sdhci_prepare_data(host);
    sdhc_writel(host, cmd->arg, SDHC_ARGUMENT);
    sdhci_set_tsf_mode(host, cmd);

    if ((cmd->resp_type & RESP_136) && (cmd->resp_type & RESP_BUSY)) {
        mmc_err("host%d: Unsupported response type!\n",host->id);
        cmd->err = -EINVAL;
        sdhci_tasklet_finish(host);
        return;
    }

    if (!(cmd->resp_type & RESP_PRESENT))
        flags = SDHC_CMD_RESP_NONE;
    else if (cmd->resp_type & RESP_136)
        flags = SDHC_CMD_RESP_LONG;
    else if (cmd->resp_type & RESP_BUSY)
        flags = SDHC_CMD_RESP_SHORT_BUSY;
    else
        flags = SDHC_CMD_RESP_SHORT;

    if (cmd->resp_type & RESP_CRC)
        flags |= SDHC_CMD_CRC;
    if (cmd->resp_type & RESP_CMDCODE)
        flags |= SDHC_CMD_INDEX;

    /* CMD19 is special in that the Data Present Select should be set */
    if (data != NULL || cmd->cmd_code == SEND_TUNING_BLOCK ||
            cmd->cmd_code == SEND_TUNING_BLOCK_HS200)
        flags |= SDHC_CMD_DATA;

    mmc_trace(3, "cmd[%d],cmd = 0x%x,flags = 0x%x\n",cmd->cmd_code,SDHC_MAKE_CMD(cmd->cmd_code , flags),flags);
    sdhc_writew(host, SDHC_MAKE_CMD(cmd->cmd_code , flags), SDHC_COMMAND);
}

int mmc_send_tuning(struct mmc_host *mmc, unsigned int opcode, int *cmd_error)
{
    struct mmc_request tuning_mrq = {0};
    struct mmc_cmd tuning_cmd = {0};
    struct mmc_data tuning_data = {0};

    struct scatterlist sg = {0};
    struct tuning_blk_info tuning_info = {NULL, 0};
    void *data_buf = NULL;
    int  err = 0;

    if(mmc->card_list->card.iocfg.bus_width == BUS_WIDTH_8) {
        tuning_info.blk = (uint8_t *)tuning_blk_8bit;
        tuning_info.blk_size = sizeof(tuning_blk_8bit);
    } else if (mmc->card_list->card.iocfg.bus_width == BUS_WIDTH_4) {
        tuning_info.blk = (uint8_t *)tuning_blk_4bit;
        tuning_info.blk_size = sizeof(tuning_blk_4bit);
    } else
       return -EINVAL;

    data_buf = (void *)memalign(CACHE_ALIGNED_SIZE, ALIGN(tuning_info.blk_size,CACHE_ALIGNED_SIZE));
    if (data_buf == NULL)
        return -ENOMEM;
    (void)memset_s(data_buf, tuning_info.blk_size, 0, tuning_info.blk_size);
    sg_init_one(&sg, data_buf, tuning_info.blk_size);
    tuning_mrq.cmd = &tuning_cmd;
    tuning_mrq.data = &tuning_data;

    tuning_cmd.arg = 0;
    tuning_cmd.retries = 0;
    tuning_cmd.cmd_code = opcode;
    tuning_cmd.resp_type = MMC_RESP_R1 | MMC_CMD_ADTC;
    tuning_cmd.err = 0;
    tuning_data.err = 0;

    tuning_mrq.data->blocksz = tuning_info.blk_size;
    tuning_mrq.data->blocks = 1;
    tuning_mrq.data->data_flags = MMC_DATA_READ;
    tuning_mrq.data->sg = &sg;
    tuning_mrq.data->sg_len = 1;

    mmc_wait_for_req(mmc, &tuning_mrq);

    if (cmd_error != NULL) {
        *cmd_error = tuning_cmd.err;
        err = tuning_cmd.err;
        goto out;
    }

    if (tuning_cmd.err) {
        err = tuning_cmd.err;
        goto out;
    }

    if (tuning_data.err) {
        err = tuning_data.err;
        goto out;
    }
    if (memcmp(tuning_info.blk, data_buf, tuning_info.blk_size)) {
        err = -EIO;
    }

out:
    free(data_buf);
    return err;
}

static int sdhci_data_sync(struct mmc_data *data)
{
    unsigned long sg_phyaddr, sg_length;
    unsigned int i = 0;

    if (data->data_flags & MMC_DATA_READ) {
        for (i = 0; i < data->sg_len; i++) {
            sg_length = sg_dma_len(&data->sg[i]);
            sg_phyaddr = sg_dma_address(&data->sg[i]);
            mmc_dma_cache_inv((void*)sg_phyaddr, sg_length);
        }
    }
    return 0;
}

void mmc_do_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
    struct sdhc_host * cur_host = NULL;
    int present = 0;
    int ret = 0;
    unsigned long flags = 0;
    UINT32 timeout = SD_HCI_CMD_DATA_REQ_TIMEOUT;

    mmc_assert(mmc);
    mmc_assert(mrq);
    cur_host = mmc->priv;
    mmc_assert(cur_host);

    (void)mmc_sem_pend(cur_host->sem_id, MMC_SEM_WAIT_FOREVER);

    cur_host->mrq = mrq;
    cur_host->data = mrq->data;

    if (SDHC_DETECTION_BROKEN(cur_host) || cur_host->forceSWDetect) {
        present = 1;
    }  else {
        present = SDHCI_PLUG_STATE(cur_host);
    }
    if(!present || (cur_host->flags & SDHC_DEVICE_DEAD) ||
            cur_host->priv_status.select.detect_change) {
        mrq->cmd->err = -EIO;
        mmc_err("card is not present!\n");
        sdhci_enable_card_detection(cur_host);
        (void)mmc_sem_post(cur_host->sem_id);
        return;
    } else {
        sd_hci_exec_cmd(cur_host, mrq->cmd, mrq->data);
    }

    mmc_irq_lock(&flags);
    cur_host->wait_for_event = 1;
    mmc_irq_unlock(flags);

    if (mrq->data == NULL && cur_host->forceSWDetect) {
        timeout = SD_HCI_CMD_REQ_TIMEOUT;
    }

    ret = mmc_event_wait(&cur_host->sdhci_event, SDHC_PEND_REQUEST_DONE | SDHC_PEND_ACCIDENT, timeout);

    mmc_irq_lock(&flags);
    cur_host->wait_for_event = 0;
    mmc_irq_unlock(flags);

    if (ret != SDHC_PEND_REQUEST_DONE) {
        sdhci_dumpregs(cur_host);
        if(mmc->card_cur != NULL && is_card_present(mmc->card_cur)) {
            mmc_err("wait hw%d cmd=%d interrupt err!\n", cur_host->id, mrq->cmd->cmd_code);
        }
        if (ret == SDHC_PEND_ACCIDENT)
            mrq->cmd->err = -EIO;
        else
            mrq->cmd->err = -ETIMEDOUT;

        sdhci_do_reset(cur_host, SDHC_RESET_CMD);
        sdhci_do_reset(cur_host, SDHC_RESET_DATA);
        cur_host->mrq = NULL;
        cur_host->cmd = NULL;
        cur_host->data = NULL;

        if (mrq->done != NULL)
            mrq->done(mrq);
    }
    else if(mrq->data != NULL)
    {
        (void)sdhci_data_sync(mrq->data);
    }
    (void)mmc_sem_post(cur_host->sem_id);
}

static int sd_hci_host_config(struct sdhc_host *cur_host)
{
    struct mmc_host *mmc = NULL;
    unsigned int sdhci_caps[2] = {0, 0};
    int ret;
    mmc_thread task_id;
    unsigned int reg;
    unsigned short value;
    TSK_ENTRY_FUNC taskEntry = NULL;

    mmc = cur_host->mmc;
    mmc_trace(2,"id: %d, host[0x%x],mmc:[0x%8x].\n", cur_host->id, cur_host, mmc);

    if (mmc_sem_create(&(cur_host->sem_id))) {
        mmc_err("semaphore init fail!\n");
        ret = -EACCES;
        goto err;
    }

    if (mmc_mutex_init(&(cur_host->thread_mutex))) {
        mmc_err("mutex init fail!\n");
        ret = -EACCES;
        goto err;
    }

    mmc->ocr_default.bits.vdd_3v2_3v3 = 1;
    mmc->ocr_default.bits.vdd_3v3_3v4 = 1;
    mmc->ocr_default.bits.vdd_2v9_3v0 = 1;
    mmc->ocr_default.bits.vdd_3v0_3v1 = 1;

    sdhci_pltfm_init(cur_host);

    sdhci_crg_init(cur_host);
    cur_host->version = sdhc_readw(cur_host, SDHC_HOST_VERSION);
    cur_host->version = (cur_host->version & SDHC_SPEC_VER_MASK)
        >> SDHC_SPEC_VER_SHIFT;
    mmc_trace(3,"host->version = %d\n", cur_host->version);

    sdhci_caps[0] = sdhc_readl(cur_host, SDHC_CAPABILITIES);
    mmc_trace(3,"host->caps0 = 0x%x\n", sdhci_caps[0]);
    if (cur_host->version >= SDHC_SPEC_300) {
        sdhci_caps[1] = sdhc_readl(cur_host, SDHC_CAPABILITIES_1);
        mmc_trace(3,"host->caps1 = 0x%x\n", sdhci_caps[1]);
    }

    if (sdhci_caps[0] & SDHC_CAN_DO_SDMA)
        cur_host->flags |= SDHC_USE_SDMA;

    if ((cur_host->version >= SDHC_SPEC_200) &&
        (sdhci_caps[0] & SDHC_CAN_DO_ADMA2)) {
        cur_host->flags |= SDHC_USE_ADMA;
        if (sdhci_caps[0] & SDHC_CAN_64BIT)
            cur_host->flags |= SDHC_USE_ADMA_64BIT;
    }

    if (cur_host->flags & SDHC_USE_ADMA) {
        cur_host->adma_max_desc = SDMCI_ADMA_MAX_DESC;
        cur_host->adma_desc_sz = SDMCI_ADMA_DEF_SIZE;

        if (cur_host->flags & SDHC_USE_ADMA_64BIT) {
            cur_host->adma_desc_line_sz = 12;
            //host->align_bytes = 8;
        } else {
            cur_host->adma_desc_line_sz = 8;
            //host->align_bytes = 4;
        }
        cur_host->adma_desc_sz = (cur_host->adma_max_desc * 2 + 1) *
            cur_host->adma_desc_line_sz;

        mmc_trace(3,"host->adma_desc_sz = %d\n",cur_host->adma_desc_sz);
        cur_host->adma_desc = (void *)memalign(CACHE_ALIGNED_SIZE, ALIGN(cur_host->adma_desc_sz,CACHE_ALIGNED_SIZE));
        if(cur_host->adma_desc == NULL) {
            mmc_err("allocate ADMA buffer fail!\n");
            cur_host->flags &= ~SDHC_USE_ADMA;
            cur_host->adma_desc = NULL;
            ret = -ENOMEM;
            goto err;
        }
    } else {
        mmc_err("Warning! ADMA not support!\n");
        ret = -ENOSUPP;
        goto err;
    }

    sdhci_caps[1] &= ~(SDHC_SUPPORT_SDR50 | SDHC_SUPPORT_SDR104 |
            SDHC_SUPPORT_DDR50 | SDHC_CAN_DO_ADMA3);
    sdhci_caps[1] |= SDHC_USE_SDR50_TUNING;


    if (cur_host->version >= SDHC_SPEC_300)
        cur_host->max_clk = (sdhci_caps[0] & SDHC_CLOCK_V3_BASE_MASK)
            >> SDHC_CLOCK_BASE_SHIFT;
    else
        cur_host->max_clk = (sdhci_caps[0] & SDHC_CLOCK_BASE_MASK)
            >> SDHC_CLOCK_BASE_SHIFT;
    cur_host->max_clk *= 1000000;
    cur_host->clk_mul = (sdhci_caps[1] & SDHC_CLOCK_MUL_MASK) >>
        SDHC_CLOCK_MUL_SHIFT;

    mmc_trace(3, "host->max_clk = %d,host->clk_mul = %d\n",cur_host->max_clk,cur_host->clk_mul);

    if (cur_host->clk_mul) {
        cur_host->clk_mul += 1;
    }

    mmc->freq_max = cur_host->max_clk;
    if(mmc->freq_min == 0)
    {
        if (cur_host->version >= SDHC_SPEC_300) {
            if (cur_host->clk_mul) {
                mmc->freq_min = (cur_host->max_clk * cur_host->clk_mul) / 1024;
                mmc->freq_max = cur_host->max_clk * cur_host->clk_mul;
            } else {
                mmc->freq_min = cur_host->max_clk / SDHC_MAX_DIV_SPEC_300;
            }
        } else {
            mmc->freq_min = cur_host->max_clk / SDHC_MAX_DIV_SPEC_200;
        }
    }
    mmc_trace(3,"mmc->freq_max = %d,mmc->freq_min = %d\n", mmc->freq_max, mmc->freq_min);

    mmc->caps.bits.cap_sdio_irq = 1;
    mmc->caps.bits.cap_erase = 1;
    mmc->caps.bits.cap_CMD23 = 1;

    if (((cur_host->version >= SDHC_SPEC_300) &&
        (cur_host->flags & SDHC_USE_ADMA)) ||
            !(cur_host->flags & SDHC_USE_SDMA)) {
        cur_host->flags |= SDHC_AUTO_CMD23;
        mmc_trace(3, "Auto-CMD23 available!\n");
    }

    if (!cur_host->quirks.bits.quirk_force_1_bit_data) {
        mmc->caps.bits.cap_4_bit = 1;
    }
    if (sdhci_caps[0] & SDHC_CAN_DO_HISPD) {
        mmc->caps.bits.cap_mmc_highspeed = 1;
        mmc->caps.bits.cap_sd_highspeed = 1;
    }

    if (!cur_host->quirks2.bits.quirk2_no_1_8_v) {
        mmc->caps.bits.cap_UHS_SDR12 = 1;
        mmc->caps.bits.cap_UHS_SDR25 = 1;
        mmc->caps.bits.cap_UHS_SDR50 = 1;
        mmc->caps.bits.cap_UHS_SDR104 = 1;
    }

    if (sdhci_caps[1] & SDHC_DRIVER_TYPE_A)
        mmc->caps.bits.cap_driver_type_A = 1;
    if (sdhci_caps[1] & SDHC_DRIVER_TYPE_C)
        mmc->caps.bits.cap_driver_type_C = 1;
    if (sdhci_caps[1] & SDHC_DRIVER_TYPE_D)
        mmc->caps.bits.cap_driver_type_D = 1;

#if defined(LOSCFG_DRIVERS_SD_PROT_VER2)
    mmc_trace(MMC_TRACE_WARNING,
        "host%d with protocol ver2 doesnot support VDD1.8\n",
            cur_host->id);
#else
    if (sdhci_caps[0] & SDHC_CAN_VDD_180)
    {
        mmc->ocr_default.bits.vdd_1v65_1v95 = 1;
        mmc_trace(MMC_TRACE_WARNING, "VDD1.8 support\n");
    }
#endif
    if (cur_host->flags & SDHC_USE_ADMA) {
        mmc->max_request_size = cur_host->adma_max_desc * 65536;
        mmc_trace(MMC_TRACE_WARNING, "SDHC_USE_ADMA\n");
    }

    mmc->max_blk_size = (sdhci_caps[0] & SDHC_MAX_BLOCK_MASK) >>
        SDHC_MAX_BLOCK_SHIFT;
    if (mmc->max_blk_size >= 3) {
        mmc_err("Invalid maximum block size, assuming 512 bytes!\n");
        mmc->max_blk_size = 0;
    }
    mmc->max_blk_size = 512 << mmc->max_blk_size;
    mmc->max_blk_num = (mmc->max_request_size / mmc->max_blk_size);
    mmc_trace(3, "max_blk_size  = %d, max_blk_num = %d\n",mmc->max_blk_size, mmc->max_blk_num);

    cur_host->flags |= SDHC_HOST_IRQ_STATUS;
    sdhci_host_quirks(cur_host);
    sdhci_init(cur_host, 0);

    (void)mmc_event_init(&(cur_host->sdhci_event));

    ret = request_irq(cur_host->irq_num, (irq_handler_t)sdhci_irq, 0, "MMC-SD", cur_host);
    if (ret) {
        mmc_err("request irq for himci is err\n");
        ret = -EACCES;
        goto err;
    }

    sdhci_enable_card_detection(cur_host);

    sdhci_pltfm_set_io(cur_host);

    value = sdhc_readw(cur_host, SDHC_CLOCK_CONTROL);
    value |= SDHC_CLOCK_INT_EN | SDHC_CLOCK_PLL_EN;
    sdhc_writew(cur_host, value, SDHC_CLOCK_CONTROL);

    reg = 200000;
    while (1)
    {
        value = sdhc_readw(cur_host, SDHC_CLOCK_CONTROL);
        if (value & (unsigned short)SDHC_CLOCK_INT_STABLE) {
            break;
        }
        if (reg == 0)
        {
            mmc_trace(6, "%d: Inter clk never stabilized.\n", cur_host->id);
            ret = -EBUSY;
            goto err;
        }
        reg--;
    }

    value |= SDHC_CLOCK_CARD_EN;
    sdhc_writew(cur_host, value, SDHC_CLOCK_CONTROL);
    mmc_delay_us(100);

    cur_host->priv_status.select.last_detect_status = CARD_IS_PLUGOUT;
    if(cur_host->forceSWDetect) {
        taskEntry = (TSK_ENTRY_FUNC)sdhci_sw_detect;
    } else {
        taskEntry = (TSK_ENTRY_FUNC)sd_mci_pre_detect_card;
    }
    ret = mmc_thread_create(5,
            (TSK_ENTRY_FUNC)taskEntry,
            SDMCI_STACKSIZE,
            (AARCHPTR)cur_host,
            "sdmci_Pre_detect",
            &task_id);
    if (ret) {
        mmc_trace(5,"sdhci_Pre_detect create fail\n");
        goto err;
    }

    return 0;
err:
    mmc_err("err while initialize MMC %d!\n",cur_host->id);
    return ret;
}

mmc_event  g_host_event;
UINT32 g_host_total_event = 0;

int mmc_pthread_event_init(void)
{
    (void)mmc_event_init(&g_host_event);
    return 0;
}

static inline void mmc_signal_sdio_irq(struct mmc_card *card)
{
    card->host->is_sdio_irq_pending = true;
    if (card->is_sdio_event_useable)
        (void)mmc_event_signal(&card->sdio_event, 1);
}

static void sdhci_enable_sdio_irq_nolock(struct sdhc_host *host, int en)
{
    if (!(host->flags & SDHC_DEVICE_DEAD)) {
        if (en)
            host->irq_enable |= SDHC_INT_CARD_INT;
        else
            host->irq_enable &= ~SDHC_INT_CARD_INT;

        sdhci_enable_plug_irq(host, host->irq_enable);
    }
}

void sd_mci_pre_detect_card(struct sdhc_host *cur_host)
{
    bool present = false;
    mmc_trace(0, "host %d is pre detecting...", cur_host->id);
    (void)mmc_mutex_lock(cur_host->thread_mutex, MMC_MUTEX_WAIT_FOREVER);
    if (SDHC_DETECTION_BROKEN(cur_host)) {
        present = true;
    } else {
        present = !!(sdhc_readl(cur_host, SDHC_PRESENT_STATE) & SDHC_CARD_PRESENT);
    }
    if (present) {
        mmc_trace(3, "host %d is pre detecting...\n", cur_host->id);
        sdhci_init(cur_host, 0);
        sdhci_enable_card_detection(cur_host);
        if (!(cur_host->mmc->caps.bits.cap_nonremovable) &&
                !SDHC_DETECTION_BROKEN(cur_host))
            mmc_printf(2, "host %d a card is plugged.\n", cur_host->id);

        (void)mmc_do_detect(cur_host->mmc);
    }
    (void)mmc_event_signal(&cur_host->detectEvt, HOST_PRE_INIT_DONE);
    (void)mmc_mutex_unlock(cur_host->thread_mutex);
    SDHCI_UPDATA_TEST_COUNTER(cur_host->mmc);
}

void sdhci_hndl_plug_event(struct mmc_host* mmc, bool in)
{
    INT32 rv;
    struct sdhc_host* cur_host = (struct sdhc_host *)mmc->priv;

    if (in) {
        sdhci_init(cur_host, 0);
        sdhci_enable_card_detection(cur_host);
        //only print the card is plugged when the card is detect by hardware.
        //or else the host just assume the card is in the slot.
        if (!(cur_host->mmc->caps.bits.cap_nonremovable) &&
                !cur_host->forceSWDetect &&
                !SDHC_DETECTION_BROKEN(cur_host)) {
            mmc_printf(MMC_PRINTF_WARN, "host %d a card is plugged.\n", cur_host->id);
        }
        rv = mmc_do_detect(cur_host->mmc);
        if (rv == 0) {
            cur_host->priv_status.select.last_detect_status = CARD_IS_PLUGIN;
        }
    } else {
        mmc_printf(MMC_PRINTF_WARN, "host %d a card is unplugged.\n", cur_host->id);
        if (mmc->card_cur != NULL)
            mmc_del_card(mmc);
        cur_host->priv_status.select.last_detect_status = CARD_IS_PLUGOUT;
    }
}

static void sd_mci_pthread(void)
{
    int cardState;
    unsigned int host_active = 0;
    unsigned int i = 0;
    unsigned int isr = 0;
    unsigned long flags = 0;
    unsigned char detect_change = 0;

    struct sdhc_host *cur_host = NULL;
    struct mmc_host *mmc = NULL;
    struct mmc_card *card = NULL;

    while(1)
    {
        host_active = mmc_event_wait(&g_host_event, g_host_total_event, SDHC_PTHREAD_EVENT_TIMEOUT);
        if (host_active & (~g_host_total_event)) {
            mmc_err("check pthread event! host_active = 0x%x\n", host_active);
            continue;
        }
        for (i = 0; i < MAX_MMC_NUM; i++) {
            if (!(host_active & (1 << i)))
                continue;

            if ((mmc = get_mmc_host(i)) == NULL) {
                continue;
            }

            cur_host = (struct sdhc_host *)mmc->priv;
            mmc_irq_lock(&flags);
            isr = cur_host->thread_isr;
            cur_host->thread_isr = 0;
            detect_change = cur_host->priv_status.select.detect_change;
            cur_host->priv_status.select.detect_change = 0;
            mmc_irq_unlock(flags);

            cardState = sdhc_readl(cur_host, SDHC_PRESENT_STATE) & SDHC_CARD_PRESENT;
            if (detect_change) {
                detect_change = 0;
                if (cardState && mmc->card_cur) {
                    mmc_printf(2, "detect_change isr = 0x%x.\n",isr);
                    isr &= ~(SDHC_INT_CARD_REMOVE);
                    mmc_del_card(mmc);
                    cur_host->priv_status.select.last_detect_status = CARD_IS_PLUGOUT;
                }
            }

            if ((isr & SDHC_INT_CARD_INSERT) && cardState) {
                sdhci_hndl_plug_event(mmc, true);
                SDHCI_UPDATA_TEST_COUNTER(mmc);
            }

            if ((isr & SDHC_INT_CARD_REMOVE) && !cardState) {
                sdhci_hndl_plug_event(mmc, false);
                SDHCI_UPDATA_TEST_COUNTER(mmc);
            }
            if (isr & SDHC_INT_CARD_INT) {
                card = cur_host->mmc->card_cur;
                mmc_signal_sdio_irq(card);
            }
        }
    } while(1);/*lint !e506*/
}


/*
 * Interrupt handling
 * */
static void sdhci_finish_command(struct sdhc_host *cur_host)
{
    int i = 0;
    struct mmc_cmd *cmd = cur_host->cmd;

    mmc_assert(cur_host->cmd);

    if(cmd == NULL)
    {
        return;
    }

    if (cmd->resp_type & RESP_PRESENT) {
        if (cmd->resp_type & RESP_136) {
            for (; i < 4; i++) {
                cmd->resp[i] = sdhc_readl(cur_host, SDHC_RESPONSE + (3-i)*4) << 8;
                if (i != 3)
                    cmd->resp[i] |=
                        sdhc_readb(cur_host, SDHC_RESPONSE + (3-i)*4 - 1);
            }
        } else {
            cur_host->cmd->resp[0] = sdhc_readl(cur_host, SDHC_RESPONSE);
        }
    }

    if (cur_host->data == NULL || (cmd != NULL && cmd->cmd_code == STOP_TRANSMISSION))
        sdhci_tasklet_finish(cur_host);

}

void sdhci_cmd_irq(struct sdhc_host *cur_host, unsigned int intmask, unsigned int  *mask)
{
    mmc_assert(intmask);

    if (cur_host->cmd == NULL) {
        mmc_trace(5,"Got command interrupt 0x%x.\n",cur_host->cmd);
        return;
    }

    if (intmask & SDHC_INT_TIMEOUT)
        cur_host->cmd->err = -ETIMEDOUT;
    else if (intmask & (SDHC_INT_CRC | SDHC_INT_END_BIT | SDHC_INT_INDEX))
        cur_host->cmd->err = -EILSEQ;

    if (cur_host->data == NULL && cur_host->cmd->err) {
        sdhci_tasklet_finish(cur_host);
        return;
    }

    if (cur_host->cmd->resp_type & RESP_BUSY)
        return;

    if (intmask & SDHC_INT_RESPONSE)
        sdhci_finish_command(cur_host);
}

static void sdhci_data_irq(struct sdhc_host *cur_host, unsigned int intmask)
{
    unsigned int command;

    mmc_assert(intmask);
    mmc_trace(5,"intr status:0x%x\n", sdhc_readl(cur_host, SDHC_INT_STATUS));

    if (cur_host->data == NULL || (cur_host->cmd->cmd_code == STOP_TRANSMISSION)) {
    mmc_trace(3,"irq,data = 0x%p, host->cmd->resp_type = 0x%x\n",cur_host->data, cur_host->cmd->resp_type);
        if (cur_host->cmd != NULL && (cur_host->cmd->resp_type & RESP_BUSY)) {
            if (intmask & SDHC_INT_DATA_TIMEOUT) {
                cur_host->cmd->err = -ETIMEDOUT;
                sdhci_tasklet_finish(cur_host);
                return;
            }
            if (intmask & SDHC_INT_DATA_END) {
                sdhci_finish_command(cur_host);
                return;
            }
        }
    }
    if (cur_host->data == NULL) {
        return;
    }

    if (intmask & SDHC_INT_DATA_TIMEOUT)
        cur_host->data->err = -ETIMEDOUT;
    else if (intmask & SDHC_INT_END_BIT)
        cur_host->data->err = -EILSEQ;
    else if ((intmask & SDHC_INT_DATA_CRC))
        cur_host->data->err = -EILSEQ;
    else if (intmask & SDHC_INT_ADMA_ERROR) {
        cur_host->data->err = -EIO;
    }

    if (cur_host->data->err) {
        command = SDHC_GET_CMD(sdhc_readw(cur_host, SDHC_COMMAND));
        if (command != SEND_TUNING_BLOCK && command != SEND_TUNING_BLOCK_HS200) {
            mmc_err("err = 0x%x, cmd = %d, interrupt = 0x%x\n",cur_host->data->err, command, intmask);
            sdhci_dumpregs(cur_host);
        }

        sdhci_finish_data(cur_host);
    } else {
        if (intmask & SDHC_INT_DATA_END)
            sdhci_finish_data(cur_host);
        else
            mmc_err("do check here! intmask = 0x%x\n", intmask);
    }
}

static irqreturn_t sdhci_irq(int irq, void *data)
{
    irqreturn_t result = IRQ_HANDLED;
    struct sdhc_host *cur_host = (struct sdhc_host *)data;
    unsigned int intmask;
    unsigned char curr_status;

    while((intmask = sdhc_readl(cur_host, SDHC_INT_STATUS)) != 0)
    {
        mmc_trace(4, "isr = 0x%x\n", intmask);
        sdhc_writel(cur_host, intmask, SDHC_INT_STATUS);
        if (intmask & CART_PLUG_STATE) {
            cur_host->irq_enable &= ~CART_PLUG_STATE;
            cur_host->irq_enable |= SDHCI_PLUG_STATE(cur_host) ? SDHC_INT_CARD_REMOVE : SDHC_INT_CARD_INSERT;
            sdhci_enable_plug_irq(cur_host, cur_host->irq_enable);

            sdhc_writel(cur_host, intmask & CART_PLUG_STATE, SDHC_INT_STATUS);
            cur_host->thread_isr |= intmask & CART_PLUG_STATE;
            result = IRQ_WAKE_THREAD;

            curr_status = SDHCI_PLUG_STATE(cur_host) ? CARD_IS_PLUGOUT : CARD_IS_PLUGIN;
            if (curr_status !=
                    cur_host->priv_status.select.last_detect_status)
                cur_host->priv_status.select.detect_change = 1;

            if (cur_host->wait_for_event) {
                (void)mmc_event_signal(&cur_host->sdhci_event, SDHC_PEND_ACCIDENT);
            }
            /* write event for button half to detect card */
            (void)mmc_event_signal(&g_host_event, (1U << cur_host->id));
        }

        if (intmask & SDHC_INT_CMD_MASK)
            sdhci_cmd_irq(cur_host, intmask & SDHC_INT_CMD_MASK, &intmask);

        if (intmask & SDHC_INT_DATA_MASK)
            sdhci_data_irq(cur_host, (intmask & SDHC_INT_DATA_MASK));

        if (intmask & SDHC_INT_BUS_POWER)
            mmc_err("host%d:card is consuming too much power!\n",cur_host->id);

        if (intmask & SDHC_INT_CARD_INT) {
            sdhci_enable_sdio_irq_nolock(cur_host, false);
            cur_host->thread_isr |= SDHC_INT_CARD_INT;
            result = IRQ_WAKE_THREAD;
            (void)mmc_event_signal(&g_host_event,(1U << cur_host->id));
        }

        intmask &= ~(CART_PLUG_STATE
                | SDHC_INT_CMD_MASK | SDHC_INT_DATA_MASK
                | SDHC_INT_ERROR | SDHC_INT_BUS_POWER
                | SDHC_INT_CARD_INT);
        if (intmask) {
            cur_host->errCount++;
        }
    }

    return result;
}

void sdhci_sw_detect(AARCHPTR uwPar)
{
    INT32 rv;
    INT8 plug = CARD_IS_PLUGIN;
    UINT32 status;
    struct mmc_host * mmc = NULL;
    struct mmc_card *card = NULL;
    struct sdhc_host * host = (struct sdhc_host *)uwPar;

    if(host == NULL || host->mmc == NULL)
    {
        mmc_trace(6, "host is not ready in slot %d\n");
        return;
    }

    //this thread should be triggered only when the forceSWDetect is set
    if (host->forceSWDetect == false) {
        return;
    }

    //tell the host that do not wait for this thread.
    (void)mmc_event_signal(&host->detectEvt, HOST_PRE_INIT_DONE);
    mmc = host->mmc;

    while (true) {
        (void)mmc_mutex_lock(host->thread_mutex, MMC_MUTEX_WAIT_FOREVER);

        mmc_trace(3, "host id=%d\n", host->id);
        card = mmc->card_cur;
        if (card != NULL && is_card_present(card)) {
            if(is_card_removeable(card) == 0) {
                mmc_trace(MMC_TRACE_WARNING, "software detection should not be used"
                        " on EMMC in slot %d\n", host->id);
                (void)mmc_mutex_unlock(host->thread_mutex);
                return;
            }
            plug = CARD_IS_PLUGIN;
            rv = get_card_status(card, &status, MMC_SW_DET_RETRIES);
            if (rv == 0) {
                mmc_trace(3, "slot%d: card in\n", host->id);
                (void)mmc_mutex_unlock(host->thread_mutex);
                SDHCI_UPDATA_TEST_COUNTER(mmc);
                msleep(SD_MCI_SW_DET_SLEEP);
            } else {
                mmc_trace(6, "slot%d: card status error, remove card.\n", host->id);
                sdhci_hndl_plug_event(mmc, false);
                if (mmc->card_cur != NULL) {
                    mmc_trace(6, "ERR: slot%d: card still there!!\n", host->id);
                }
                (void)mmc_mutex_unlock(host->thread_mutex);
                SDHCI_UPDATA_TEST_COUNTER(mmc);
            }
        } else {
            mmc_trace(3, "slot%d: no card\n", host->id);
            if(plug == CARD_IS_PLUGIN) {
                mmc_trace(3, "slot%d: last card status is in\n", host->id);
                sdhci_hndl_plug_event(mmc, true);
            } else {
                mmc_trace(3, "slot%d: last card status is out\n", host->id);
                rv = mmc_do_detect(host->mmc);
                if (rv == 0) {
                    host->priv_status.select.last_detect_status = CARD_IS_PLUGIN;
                }
            }

            plug = CARD_IS_PLUGOUT;
            if (mmc->card_cur != NULL) {
                mmc_printf(MMC_PRINTF_WARN, "host %d a card is plugged.\n", host->id);
                (void)mmc_mutex_unlock(host->thread_mutex);
                SDHCI_UPDATA_TEST_COUNTER(mmc);
                msleep(SD_MCI_SW_DET_SLEEP);
            } else {
                (void)mmc_mutex_unlock(host->thread_mutex);
                SDHCI_UPDATA_TEST_COUNTER(mmc);
                msleep(SD_MCI_SW_DET_SLEEP * 2);
            }
        }
    }
}

void hisi_sdio_init_done(UINT32 slot)
{
    struct mmc_host *mmc = NULL;
    struct sdhc_host * cur_host = NULL;

    mmc_event *detectEv = NULL;
    UINT32 waitMode = LOS_WAITMODE_AND;
    UINT32 waitMask = HOST_PRE_INIT_DONE;
    UINT32 timeout = SDHC_PTHREAD_EVENT_TIMEOUT;

    while(get_mmc_host(slot) == NULL || get_mmc_host(slot)->priv == NULL)
    {
        mmc_trace(6, "host not ready\n");
        msleep(500);
    }

    mmc = get_mmc_host(slot);
    cur_host = (struct sdhc_host *)mmc->priv;
    detectEv = &cur_host->detectEvt;

    //wait until the pre-detect thread is done.
    //but we should not clear it so that you can call it everywhere else.
    (void)LOS_EventRead(detectEv, waitMask, waitMode, timeout);

}

static int sd_mci_probe(struct platform_device *dev)
{
    mmc_thread task_id;
    static bool mmc_initialized = false;
    int ret;
    struct mmc_host *cur_mmc = NULL;
    struct sdhc_host *host = NULL;
    struct resource *res = NULL;

    cur_mmc = (struct mmc_host *)zalloc(sizeof(struct mmc_host));
    if (cur_mmc == NULL) {
        mmc_err("no mem for mmc_host\n");
        goto error;
    }
    host = (struct sdhc_host *)zalloc(sizeof(struct sdhc_host));
    if (host == NULL) {
        mmc_err("no mem for sdhci\n");
        goto error;
    }

    (void)mmc_event_init(&host->detectEvt);
    host->mmc = cur_mmc;
    cur_mmc->priv = (void *)host;
    host->id = (uint32_t)dev->id;
    res = platform_get_resource(dev, IORESOURCE_MEM, 0);
    if(res == NULL)
        goto error;
    host->base = platform_ioremap_resource(res);

    res = platform_get_resource(dev, IORESOURCE_IRQ, 0);
    if(res == NULL)
        goto error;
    host->irq_num = res->start;

    if (res->desc & PDR_DESC_SDHC_DET_BOKEN) {
        SDHC_DETECTION_BROKEN(host) = 1;
        mmc_trace(6, "host%d: detection is broken\n", host->id);
    }

    if (res->desc & PDR_DESC_SDHC_FORCESWDETECT) {
        host->forceSWDetect = true;
        mmc_trace(6, "host%d: force software detection\n", host->id);
    } else {
        host->forceSWDetect = false;
    }

    g_host_total_event |= (1U << host->id);
    ret = sd_hci_host_config(host);
    if (ret) {
        goto error;
    }
    (void)set_mmc_host(host->mmc, host->id);
    (void)mmc_event_signal(&g_host_event, g_host_total_event);
    if(!mmc_initialized){
        mmc_initialized = true;
        ret = mmc_thread_create(5,
            (TSK_ENTRY_FUNC)sd_mci_pthread,
            SDMCI_STACKSIZE,
            (AARCHPTR)NULL,
            "sdmci_detect",
            &task_id);
        if (ret) {
            mmc_trace(5,"sdmci_detect create fail\n");
            goto error;
        }
    }

    hisi_sdio_init_done(host->id);

    return 0;
error:
    if (cur_mmc != NULL){
        free(cur_mmc);
        cur_mmc = NULL;
    }
    if (host != NULL) {
        if (host->adma_desc != NULL){
            free(host->adma_desc);
            host->adma_desc = NULL;
        }
        free(host);
        host  =  NULL;
    }

    (void)set_mmc_host(NULL,dev->id);
    mmc_err("!!!!err while initialize MMC !\n");
    return -ENOMEM;/*lint !e438*//*cur_mmc and host not used*/
}

static int sd_mci_suspend(struct device *dev)
{
    mmc_trace(6, "suspend sdmci\n");
    return 0;
}

static int sd_mci_resume(struct device *dev)
{
    mmc_trace(6, "resume sdmci\n");
    return 0;
}
static const struct dev_pm_op sd_mci_dev_pm_ops = {
    .suspend = sd_mci_suspend,
    .resume = sd_mci_resume,
};


static int sd_mci_remove(struct platform_device *dev)
{
    return 0;
}

int hisi_sdio_rescan(int slot)
{
    struct mmc_host *mmc = NULL;
    struct sdhc_host * cur_host = NULL;
    struct mmc_card *card = NULL;
    int error = 0;
    UINT8 outReg;

    mmc_trace(MMC_TRACE_DEBUG, "hisi_sdio%d_rescan\n", slot);

    if(slot < 0 || (uint32_t)slot > (get_mmc_max_num() - 1)) {
        mmc_trace(6, "invalid MMC slot, please check the argument\n");
        return -EINVAL;
    }

    hisi_sdio_init_done(slot);

    mmc = get_mmc_host(slot);
    cur_host = (struct sdhc_host *) mmc->priv;
    card = mmc->card_cur;

    if (cur_host->wait_for_event) {
        (void)mmc_event_signal(&cur_host->sdhci_event, SDHC_PEND_ACCIDENT);
    }

    if (card != NULL && is_card_present(card)) {
        if (is_card_sdio(card)) {
            error = sdio_io_rw_direct(card, 0, 0, SDIO_CCCR_IOEx, 0, &outReg);
            if (error) {
                mmc_trace(6, "card status error in slot %d, remove card.\n", cur_host->id);
                sdhci_hndl_plug_event(mmc, false);
                sdhci_hndl_plug_event(mmc, true);
            } else {
                mmc_trace(3, "card found in slot %d outReg=0x%x\n", slot, outReg);
                return 0;
            }
        } else {
            mmc_trace(6, "sd/mmc found in slot %d, rescan does not support\n", slot);
        }
    } else {
        sdhci_hndl_plug_event(mmc, true);
    }

    if(mmc->card_cur == NULL)
    {
        mmc_trace(6, "hisi_sdio_rescan failed, please reset card\n");
        return -EBUSY;
    }
    return 0;
}
static struct platform_driver sd_mci_driver[2] = {
    {
        .probe      = sd_mci_probe,
        .remove     = sd_mci_remove,
        .driver     = {
            .name   = "sdmci0",
            .pm = &sd_mci_dev_pm_ops,
        },
    },
    {
        .probe      = sd_mci_probe,
        .remove     = sd_mci_remove,
        .driver     = {
            .name   = "sdmci1",
            .pm = &sd_mci_dev_pm_ops,
        },
    }
};

static int sdhci_drv_init(void)
{
    int status = 0;
    static int initialized = 0;

    (void)mutex_lock(&drv_mutex);

    if (initialized == 0) {
        status = mmc_alloc_mmc_list();
        if (status) {
            goto end;
        }
        status = block_init();
        if (status) {
            mmc_free_mmc_list();
            goto end;
        }
        status = mmc_pthread_event_init();
        if (status) {
            block_exit();
            mmc_free_mmc_list();
            goto end;
        }
#ifdef LOSCFG_FS_PROC
        status = ProcMciInit();
        if (status != 0) {
            PRINT_ERR("create mci proc failed!\n");
        }
#endif
        initialized = 1;
    }
end:
    (void)mutex_unlock(&drv_mutex);
    return status;
}

int sd_mci_init(void)
{
    int status;
    int i;
    int count = sizeof(sd_mci_driver) / sizeof(sd_mci_driver[0]);

    status = sdhci_drv_init();
    if (status) {
        return status;
    }

    for (i = 0; i < count; ++i) {
        status = platform_driver_register(&sd_mci_driver[i]);
        if (status != LOS_ERRNO_DRIVER_DRIVER_REGISTERED &&
            status != LOS_OK) {
            return status;
        }
    }
    return 0;
}

void sd_mci_exit(void)
{
    int i;
    int count = sizeof(sd_mci_driver) / sizeof(sd_mci_driver[0]);
    for (i = 0; i < count; ++i) {
        (void)platform_driver_unregister(&sd_mci_driver[i]);
    }
}

int SD_MMC_Host_init(void)
{
    return sd_mci_init();
}

int MMC_HostInitById(unsigned int id)
{
    int status;
    unsigned int count = sizeof(sd_mci_driver) / sizeof(sd_mci_driver[0]);

    if (id >= count) {
        return -EINVAL;
    }

    status = sdhci_drv_init();
    if (status != 0) {
        return status;
    }

    status = platform_driver_register(&sd_mci_driver[id]);
    if (status != LOS_ERRNO_DRIVER_DRIVER_REGISTERED) {
        return status;
    } else {
        return 0;
    }
}

